package main

import (
	"log"

	"github.com/gotk3/gotk3/gdk"
	"github.com/gotk3/gotk3/glib"
	"github.com/gotk3/gotk3/gtk"
)

type TermUi struct {
	tv *gtk.TextView
	tl *gtk.Label

	//
	adrs string
	path string

	//
	que chan string
}

//
// 通过 glib.IdleAdd() 方法， 提供跨越线程的消息传递。
//
func (ui *TermUi) AddMessage(msg string) {

	glib.IdleAdd(func() {
		//
		buf, _ := ui.tv.GetBuffer()
		ite := buf.GetEndIter()
		buf.InsertWithTagByName(ite, msg+"\n", "txt")

		//
		mk := buf.CreateMark("end", ite, true)
		ui.tv.ScrollToMark(mk, 0, true, 0, 0.5)
		buf.DeleteMark(mk)
	})
	return
}

func (ui *TermUi) SetAddrInfo(msg string) {
	glib.IdleAdd(func() {
		ui.adrs = msg
		ui.tl.SetText(ui.adrs + "  " + ui.path)
	})
	return
}

func (ui *TermUi) SetPathInfo(msg string) {
	glib.IdleAdd(func() {
		ui.path = msg
		ui.tl.SetText(ui.adrs + "  " + ui.path)
	})
	return
}

func (ui *TermUi) PostQuit() {
	glib.IdleAdd(func() {
		gtk.MainQuit()
	})
}

func main() {

	//
	ui := &TermUi{nil, nil, "----", "/", nil}
	ui.que = make(chan string, 10)

	// Initialize GTK without parsing any command line arguments.
	gtk.Init(nil)

	// Create a new toplevel window, set its title, and connect it to the
	// "destroy" signal to exit the GTK main loop when it is destroyed.
	win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	if err != nil {
		log.Fatal("Unable to create window:", err)
	}
	win.SetTitle("udp.osc.term")
	win.SetDefaultSize(800, 600)
	win.SetPosition(gtk.WIN_POS_CENTER)
	win.Connect("destroy", func() {
		gtk.MainQuit()
	})

	blyt, err := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 2)
	if err != nil {
		log.Fatal("box layout")
	}

	tv, _ := gtk.TextViewNew()
	tv.SetHExpand(true)
	tv.SetVExpand(true)
	tv.SetMarginStart(5)
	tv.SetEditable(false)
	ui.tv = tv

	// note tag : https://developer.gnome.org/gtk3/stable/GtkTextTag.html
	buf, _ := tv.GetBuffer()
	buf.CreateTag("cmd", map[string]interface{}{"foreground": "#367ECD", "font": "Mono", "size-points": 11})
	buf.CreateTag("txt", map[string]interface{}{"foreground": "#77BBCB", "font": "Mono", "size-points": 11, "left_margin": 20})

	//
	tr, _ := gtk.ScrolledWindowNew(nil, nil)
	tr.Add(tv)
	tr.SetPolicy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS)
	blyt.PackStart(tr, true, true, 0)

	// Create a new label widget to show in the window.
	ll, _ := gtk.LabelNew(ui.adrs + "  " + ui.path)
	ui.tl = ll
	blyt.Add(ll)

	//
	et, _ := gtk.EntryNew()
	et.SetHExpand(true)
	et.SetIconFromIconName(0, "info")

	/*
		et.Connect("changed", func(et *gtk.Entry) {
			bf, _ := et.GetBuffer()
			ss, _ := bf.GetText()
			log.Println("xxx:", ss)
		})
	*/

	et.Connect("activate", func(ent *gtk.Entry) {
		ebf, _ := ent.GetBuffer()
		ss, _ := ebf.GetText()
		if len(ss) > 0 {

			//
			ebf.DeleteText(0, -1)
			buf, _ := tv.GetBuffer()
			ite := buf.GetEndIter()
			buf.InsertWithTagByName(ite, ">> "+ss+"\n", "cmd")

			//
			mk := buf.CreateMark("end", ite, true)
			tv.ScrollToMark(mk, 0, true, 0, 0.5)
			buf.DeleteMark(mk)

			// send to route
			ui.que <- ss
		}

	})

	et.Connect("key-press-event", func(ent *gtk.Entry, ev *gdk.Event) bool {
		// event := *(*gdk.EventKey)(unsafe.Pointer(&ctx))
		kev := &gdk.EventKey{ev}
		ikey := kev.KeyVal()

		//fmt.Println("key:", ikey)

		if ikey == gdk.KEY_Up {
			return true
		} else if ikey == gdk.KEY_Tab {
			return true
		} else {
			return false
		}
	})

	blyt.Add(et)

	// Recursively show all widgets contained in this window.
	win.Add(blyt)
	win.ShowAll()

	/**/
	go SendThread(ui)

	// Begin executing the GTK main loop.  This blocks until gtk.MainQuit() is run.
	gtk.Main()
}
